import java.io.*;
import java.net.*;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;

import javax.net.ssl.SSLSocket;


//import javax.security.cert.X509Certificate;
import java.security.KeyStore;
import java.security.Principal;

import java.security.cert.X509Certificate;

public class NewClient  {

	// Declaration section
	// clientClient: the client socket
	// os: the output stream
	// is: the input stream
	//static SSLSocketFactory sslsocketfactory = null;
	// static SSLSocket sslClientsocket = null;

	//static Socket clientSocket = null;
	static PrintStream os = null;
	static DataInputStream is = null;
	static BufferedReader cmdGetter = null;
	static BufferedReader statusReader = null;
	static boolean closed = false;
	static boolean closed2 = false;
	static SSLSocket socket =null;
	static String FileName=null;
	static String Command=null;
	static String comm=null;
	static int commvalue;
	static BufferedWriter cmdSender;
	static String commInd[];


	public static void main(String[] args) throws Exception{

		// The default port	

		int port_number=2224;
		String host="localhost";
		String tStore="new_client.jks";
		String passp="ashishsh";
		
		if (args.length < 4)
		{
			System.out.println("Usage: java MultiThreadChatClient  \n"+
					"Now using host="+host+", port_number="+port_number);
		} else {
			host=args[0];
			port_number=Integer.valueOf(args[1]).intValue();
			tStore=args[2];
			passp=args[3];
		}
		// Initialization section:
		// Try to open a socket on a given host and port
		// Try to open input and output streams

		SSLSocketFactory factory = null;
		try {
			System.setProperty("javax.net.ssl.trustStore", tStore);
			System.setProperty("javax.net.ssl.trustStorePassword", passp);
			SSLContext ctx;
			KeyManagerFactory kmf;
			KeyStore ks;
			char[] passphrase = passp.toCharArray();

			ctx = SSLContext.getInstance("SSL");
			kmf = KeyManagerFactory.getInstance("SunX509");
			ks = KeyStore.getInstance("JKS");

			ks.load(new FileInputStream(tStore), passphrase);

			kmf.init(ks, passp.toCharArray());
			ctx.init(kmf.getKeyManagers(), null, null);

			factory = ctx.getSocketFactory();
		} catch (Exception e) {
			throw new IOException(e.getMessage());
		}

		socket = (SSLSocket)factory.createSocket(host, port_number);

		/*
		 * send http request
		 *
		 * See SSLSocketClient.java for more information about why
		 * there is a forced handshake here when using PrintWriters.
		 */
		socket.startHandshake();
		try {
			//clientSocket = new Socket(host, port_number);

			SSLSession session = socket.getSession();
		    X509Certificate cert;
		    try {
		    	
		      cert = (X509Certificate) session.getPeerCertificates()[0];
		    } catch (SSLPeerUnverifiedException e) {
		      System.err.println(session.getPeerHost() + " did not present a valid certificate.");
		      return;
		    }
		    //System.out.println(session.getPeerHost() + " has presented a certificate belonging to:");
		    Principal p = cert.getSubjectDN();
		   int to= p.getName().indexOf("=");
		    int frm=p.getName().indexOf(",");
		    
		    String CN=p.getName().substring(to+1, frm);
		   /*
		    System.out.println("\t[" + p.getName() + "]");
		    System.out.println("The certificate bears the valid signature of:");
		    System.out.println("\t[" + cert.getIssuerDN().getName() + "]");

		    System.out.println("CN:"+CN);*/
		    
		    
			cmdGetter = new BufferedReader(new InputStreamReader(System.in));
			os = new PrintStream(socket.getOutputStream());
			is = new DataInputStream(socket.getInputStream());
			statusReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			cmdSender = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		} catch (UnknownHostException e) {
			System.err.println("Don't know about host "+host);
		} catch (IOException e) {
			System.err.println("Couldn't get I/O for the connection to the host "+host);
		}



		if (socket != null && os != null && is != null) {
			try {







				loop:while(true)
				{
					System.out.print("> ");
					Command = cmdGetter.readLine();

					if(valid())
					{
						cmdSender.write(Command + '\n');
						cmdSender.flush();
					}
					else{
						System.out.println("wrong command or arguments");
						continue ;
					}
					
					/*String status =statusReader.readLine();
					if(status.equals("ok")){
						System.out.println("status receiver : "+status);
						
					}
					else{
					System.out.println("status receiver : "+status);
					continue;
					}*/

					swit: switch(commvalue){
					case 0:
					{

						String strFileSave = "." + "/" + FileName;
						BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
						
						//System.out.print("\nReceiving length...");
						byte[] bufLen = new byte[8];
						bis.read(bufLen);
						long fileLen = BytesToLong(bufLen, 0);
						//System.out.println(" Length of file: " + fileLen);
						
						if(fileLen == 0)
						{
						    System.out.println("\nThe file '" + FileName + "' does not exist on the server!\n");
						    break swit;
						}

						System.out.print("Receiving file " + FileName + "...");
						BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(strFileSave));
						byte[] bufTemp = new byte[1024];
						long lRcvd = 0;
						while(lRcvd < fileLen)
						{
						    int len = bis.read(bufTemp);
						    bos.write(bufTemp, 0, len);
						    bos.flush();
						    lRcvd += len;
						}

						bos.close();
						System.out.print(" Saved as " + strFileSave + "!\n\n");
						
						

						break swit;
					}
					case 1:
					{
						String strFileSend = "." + "/" + FileName;

						File fFileToSend = new File(strFileSend);			
						if(!fFileToSend.exists())
						{
							System.out.println("\nThe file '" + FileName + "' does not exist.\n");
							break swit;
						}
						

						long iLen = fFileToSend.length();
						BufferedInputStream bis = new BufferedInputStream(new FileInputStream(strFileSend));
						BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

			//System.out.print("Transferring length...");
						bos.write(LongToBytes(iLen));
						bos.flush();
			//System.out.println(" Length of file: " + iLen);

						System.out.print("Transferring file " + strFileSend + "...");
						byte[] bufTemp = new byte[1024];
						int len = 0;
						while((len = bis.read(bufTemp)) > 0)
						{
						    bos.write(bufTemp, 0, len);
						    bos.flush();
						}

						bis.close();
						System.out.print(" Sent!\n\n");
						
						
						break swit;
					}
					case -1:
						break loop;
						
					case 3:
						break loop;

					default:
						break swit;

					}

					//change
				}
			//added later

			os.close();
			is.close();
			socket.close();   
			} catch (IOException e) {
				System.err.println("IOException:  " + e);
			}
		}

	}   

	public static boolean valid(){
		if(Command.equals(""))
		{
			comm=null;
			commvalue=-1;
			return false;
		}
		commInd = Command.split(" ");
		if((commInd[0].equals("r")||commInd[0].equals("w"))&&commInd.length==2)
		{
			comm=commInd[0];
			if(commInd[0].equals("r"))
				commvalue=0;
			else if(commInd[0].equals("w"))
				commvalue=1;
			else 
				commvalue=-1;

			if(commInd[1].contains("/"))
			{
				int beginIndex=commInd[1].lastIndexOf('/');
				String temp=commInd[1].substring(beginIndex+1);
				FileName=temp;

			}else
			{
				FileName=commInd[1];
	
			}
//			FileName=commInd[1];

			//System.out.println("filename is "+FileName);
			return true;
		}
		else{
			if(commInd[0].equals("exit"))
			{
				comm=commInd[0];
				commvalue=3;
				return true;

			}
			else{
				comm=null;
				commvalue=-1;
				return false;
			}
			
		}
	}
	public static void  receiveFile(String file){
		try{
			if(file==null){
				file="temp"+Math.random()+".txt";

			}
			byte[] receivedData = new byte[8192];
			BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
			int in;
			while ((in = bis.read(receivedData)) != -1){
				bos.write(receivedData,0,in);
			}
			//		bos.close();
		}
		catch (IOException e){
			e.printStackTrace();
		}
	}
	 public static byte[] LongToBytes(long n)
	    {
		byte[] bytearr = new byte[8];
		bytearr[7] = (byte) (n);
		n >>>= 8;
		bytearr[6] = (byte) (n);
		n >>>= 8;
		bytearr[5] = (byte) (n);
		n >>>= 8;
		bytearr[4] = (byte) (n);
		n >>>= 8;
		bytearr[3] = (byte) (n);
		n >>>= 8;
		bytearr[2] = (byte) (n);
		n >>>= 8;
		bytearr[1] = (byte) (n);
		n >>>= 8;
		bytearr[0] = (byte) (n);

		return bytearr;
	    }
	    
	    // Converts a byte array into a Long
	    public static long BytesToLong(byte[] b, int o)
	    {
		long value = 0;
		for ( int i=0; i<8; i++ )
		{ 
		    int shift = 7-i;
		    value |= (b[o+i]<<shift);
		}
		return value;
	    }   

	/*	public void run() {		
		String responseLine;
		try{
			while (!closed) {
				//send the certificate 
				//and then send "r" or "w" and a filename 
				String temp=inputLine.readLine();


				if(temp.equals("/quit"))
				{
					break;
				}

				String cmdargs[]=temp.split(" ");
				if(cmdargs.length!=2)
				{

					System.out.println("Wrong command");
					continue;
					//close
				}
				else
				{

					if(cmdargs[0].equals("r"))
					{
						FileName="temp"+cmdargs[1];
						Comm="r";
					}
					else if(cmdargs[0].equals("w"))
					{
						Comm="w";
					}

				}


				System.out.println("temp is "+ temp);
				os.println(temp); 
			}


			} catch (IOException e) {
				System.err.println("IOException:  " + e);
			}

	}

	 */
}
